public with sharing class RoleGeneratorController {
	
	
	//To Hold the values of files
	
	private Map<Integer,List<String>>  fileContentMap=null;

    //To hold the content of Uplodaed file in blob format
    public Blob contentFile{get;set;}
    
    	//To hold the content of Uplodaed file in String format
  	public   String fileContentInString {get;set;}
    
    //To hold the Lines of the File, should be seprated by new line character /n
    String[] filelines = new String[]{};
     
    
    //To hold the List of all accounts
    public List<UserRole> allRoles {get;set;}

    // To hold the name of file
    public String nameFile { get; set; }
    
    private final String DEFAULT_COLUMN_VALUE='$%#';
    
    private Map<String,Id> roleMap=null;
    
    

    // constructor to load the List of All User Roles in the system
   public RoleGeneratorController()
    { 
        
       String query= 'Select u.SystemModstamp,u.RollupDescription,u.Name,u.ParentRoleId,u.Id From UserRole u';
       
      allRoles= DbUtils.fireQuery(query);
      
    } 
    
    public void populateExistingRoleMap(){
    	Map<Id, UserRole> roles = new Map<Id, UserRole>([select id, name from UserRole]);
    	
    	if(null != roles && !roles.isEmpty()){
    		roleMap= new Map<String,Id>();
    		Set<Id> ids=roles.keySet();
    		
    		for(Id id: ids){
    			if(!roleMap.containskey(id)){
    			roleMap.put(roles.get(id).Name,id);
    			System.debug('Role id: '+id + ' name:= '+roles.get(id).Name);
    			}
    		}
    	}
    	
    	Set<String> keys=roleMap.keySet();
    	
    	for(String key : keys){
    System.debug('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ KEY:= '+key + ' value:= '+ rolemap.get(key)	);
    	}
    }
    
      /**
    <P> This method will read the file and upload the file content in the data base</P>
    */
    public Pagereference ReadFile()
    {
    	
    	//validating the file upload and file name
        if(!validate()){
         System.debug(' 333333333=');
                return null;
        }

      convertFileContentInArray();
      populateRoleMapping();
      
       populateExistingRoleMap();
      List<RoleObject> rolesList= prepareRoleRelationships();
      if(null!= rolesList && !rolesList.isEmpty()){
     
      
      prepareRoleHierarchyList(rolesList); 
      }
     
        return null;
    }
    
  
    /**
    * <P> This method is used to create a array of records uploaded in the File.</p>
    *
    *
    */   
    private void  convertFileContentInArray(){
    
    	System.debug('Started');
        if(null!=contentFile){
        	fileContentInString=contentFile.toString();
        	       	
        	if(null!=fileContentInString){
        		filelines = fileContentInString.split('\n');
        	}
        	        	
        }else{
        	 MessaageUtils.addErrorMessage('Blank file is added in the CSV file');
        }
        if(null!=filelines){
                System.debug('Number of lines in the file: ' + filelines.size());
        }
    }   
    
    
    private void populateRoleMapping(){
    	if(null!=filelines){
    		fileContentMap= new Map<Integer,List<String>>();
    		for (Integer itr=0; itr< filelines.size();itr++){
    			
    			String [] columnValues=filelines[itr].split(',');
    			List<String> columns= new List<String>();
    			for(String columnValue : columnValues){
    				System.debug('VALUE:= ' + columnValue);
    				columns.add((StringUtils.isEmpty(columnValue)?DEFAULT_COLUMN_VALUE:columnValue));
    			}
    			fileContentMap.put(itr,columns);
    		}
    		
    		System.debug(fileContentMap);
    	}
    }
    /**
    * <p>  This method is used to Prepare a Map of [parent,child] for every row of array of records of file uploaded and add that map into the List</P>
    */
   
    
    
    private List<RoleObject> prepareRoleRelationships(){
    	List<RoleObject> roles= new List<RoleObject>();
    	if(null!= fileContentMap){

    		for(Integer itr=0; itr<fileContentMap.size(); itr++){
    			
    			List<String> columns=fileContentMap.get(itr);
    			
    			String childColumnValue=StringUtils.EMPTY;
    			Integer columnIndex=0;
    			
    			for(Integer itr1=0; itr1<columns.size(); itr1++){
    				if(!DEFAULT_COLUMN_VALUE.equals(columns[itr1])){
    					childColumnValue=columns[itr1];
    					columnIndex=itr1;
    					break;
    				}
    			}
    			System.debug('##### columnValue:= #'+ childColumnValue + '@ columnIndex:= '+ columnIndex);
    			String parentColumnValue=StringUtils.Empty;
    			Integer currentIndex=columnIndex-1;
    			for (Integer reverseIdx=itr-1 ; reverseIdx>=0; reverseIdx-- ){
    				
    			
    				
    				List<String> columnsOfParentRow=fileContentMap.get(reverseIdx);
    				//System.debug('@@@@@ index:= ' + reverseIdx + ' LIST: = '+columnsOfParentRow);
    				
    				if(currentIndex>=0 && DEFAULT_COLUMN_VALUE != columnsOfParentRow.get(currentIndex)){
    					parentColumnValue= columnsOfParentRow.get(currentIndex);
    					break;
    				}
    				
    			}
    			System.debug('##### ParentcolumnValue:= '+ parentColumnValue + ' ParentcolumnIndex:= '+ currentIndex);
    			RoleObject roleObj= new RoleObject();
    			roleObj.setChildRoleName(childColumnValue);
    			roleObj.setParentRoleName(parentColumnValue);
    			System.debug('################################ child name:= '+ childColumnValue + ', := '+roleMap.get(childColumnValue));
    			roleObj.setChildRoleId(roleMap.get(childColumnValue));
    			roleObj.setParentRoleId(roleMap.get(parentColumnValue));
    			roles.add(roleObj);
    		}
    		
    	}
    	return roles;
    }
    
    private void prepareRoleHierarchyList(List<RoleObject> roleMapList){
    	
    	if(null!= roleMapList){
    		
    		for(RoleObject roleObj: roleMapList){

    			system.debug( roleObj.toString());
    			createRoleAndUpdateRoleMapForNewRole(roleObj);
    		
    		}
    	}
    	    	
    }
    
    private String[] fetchExactvaluesForRecord(String record){
    	
    	String [] recordArray= new String[2];
    	if(!StringUtils.isEmpty(record)){
    	String oriRecord=	StringUtils.remove(record, StringUtils.EMPTY);
    	System.debug('oriRecord:= ' + oriRecord);
    	}
    	return null;
    }
    
    
    private void createRoleAndUpdateRoleMapForNewRole(RoleObject roleObj){
    	
    	UserRole userRole= null;
    	
    	//Child does not exist in DB
    	if(null == roleObj.getChildRoleId() || StringUtils.isEmpty(roleObj.getChildRoleId())){
    		
    		userRole = new UserRole(name=roleObj.getChildRoleName(),RollupDescription=roleObj.getChildRoleName(),ParentRoleId=roleObj.getParentRoleId());
    				
    		if(null== userRole.ParentRoleId || StringUtils.isEmpty(userRole.ParentRoleId)){
    			userRole.ParentRoleId=roleMap.get(roleObj.getParentRoleName());
    		}
    		
    		
    		if(null !=userRole){
    			
    			Database.Saveresult result = Database.insert( userRole);
    			roleMap.put(userRole.name,result.getId());
    			
    		}
    	}
    	    			
    	
    }
    
    
     /*<P> This method is used the validate the input data</P>
    @Return: Return the Boolean value (true/false) which govern the success or failure of validation
    */
    private Boolean validate(){
        Boolean isValid=true;
        
        isValid =validateFileUploaded(isValid);
         System.debug(' isValid1111111111='+ isValid);
        isValid= validateFileExtension(nameFile);
        
        System.debug(' isValid=2222222'+ isValid);
        
        return isValid;
    }
    
    /**
    <P> This method is used to validate whether the file is uploaded or not. </p>
    */
    
    private Boolean validateFileUploaded(Boolean isValid){
                if(null==nameFile ){
                        System.debug('Isvalid:='+ isValid);
                MessaageUtils.addErrorMessage('Please select the file to upload First1');
                isValid=false;
            
          
        }
       
        return isValid;
    }
    
     private Boolean  validateFileExtension(String fileName){
     			Boolean isValid=true;	
     			final String EXTENTION ='csv';
                if(null==fileName || StringUtils.isEmpty(fileName) || !fileName.toLowerCase().endsWith(EXTENTION)){
            
	                	isValid= false;
	                MessaageUtils.addErrorMessage('Invaid format file is uploaded, please upload correct CSV file');
                }
               return isValid;
    }   
    
       /*
       1) validate the File is uplodaed or not
       2) Extention should be CSV
       3) get the content of file into an array of String
       4) Prepare a Map of [parent,child] for every row of array created in point 3 and add that map into the List
       5) 
       
       
       */
class RoleObject {
	
	String parentRoleName;
	String parentRoleId;
	
	String childRoleName;
	String childRoleId;
	
	 /* @return the parentRoleName
		 */
		public String getParentRoleName() {
			return parentRoleName;
		}

		/**
		 * @param parentRoleName the parentRoleName to set
		 */
		public void setParentRoleName(String parentRoleName) {
			this.parentRoleName = parentRoleName;
		}

		/**
		 * @return the parentRoleId
		 */
		public String getParentRoleId() {
			return parentRoleId;
		}

		/**
		 * @param parentRoleId the parentRoleId to set
		 */
		public void setParentRoleId(String parentRoleId) {
			this.parentRoleId = parentRoleId;
		}

		/**
		 * @return the childRoleName
		 */
		public String getChildRoleName() {
			return childRoleName;
		}

		/**
		 * @param childRoleName the childRoleName to set
		 */
		public void setChildRoleName(String childRoleName) {
			this.childRoleName = childRoleName;
		}

		/**
		 * @return the childRoleId
		 */
		public String getChildRoleId() {
			return childRoleId;
		}

		/**
		 * @param childRoleId the childRoleId to set
		 */
		public void setChildRoleId(String childRoleId) {
			this.childRoleId = childRoleId;
		}
		
		
}
 
}